/**
 * 
 */
package org.lex.utils;

import java.awt.Color;
import java.awt.Font;
import java.awt.Rectangle;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.SocketAddress;
import java.util.regex.Pattern;

import org.lex.swing.fontchooser.FontStyle;


/**
 * @author Daniel Liu
 */
public class Codec {
	/*
	 * FIXME ���е�decodeXXX��Ӧ���������쳣/���������������decode������£�
	 * ������nullֵ
	 */
	private static char[] HEX_DIGIT = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', };
	private static final String SEPARATOR = ",";
	private static final Pattern SPLITTER = Pattern.compile(Pattern.quote(SEPARATOR));

	public static String encodeFont(Font font) {
		return encodeFont(font, SEPARATOR);
	}

	public static String displayFont(Font font) {
		return encodeFont(font, " ");
	}

	private static String encodeFont(Font font, String separator) {
		StringBuilder buffer = new StringBuilder();
		buffer.append(font.getFamily()).append(separator);
		buffer.append(FontStyle.parseFromFont(font).getDisplayName());
		buffer.append(separator).append(font.getSize());
		return buffer.toString();
	}

	/**
	 * decode a font from the String generate by Codec.encodeFont(Font)
	 * 
	 * @param font
	 * @return Font, or null if the font String format error
	 */
	public static Font decodeFont(String font) {
		if (null == font)
			return null;
		String[] tokens = SPLITTER.split(font);
		if (3 != tokens.length)
			return null;
		return new Font(tokens[0], FontStyle.parseFromDiaplayName(tokens[1]).getStyle(), Integer.parseInt(tokens[2]));
	}

	public static String encodeIntegerArray(int[] array) {
		StringBuilder buf = new StringBuilder();
		for (int i = 0; i < array.length; i++) {
			buf.append(array[i]);
			if (i < array.length - 1)
				buf.append(SEPARATOR);
		}
		return buf.toString();
	}

	public static int[] decodeIntegerArray(String input) {
		String[] str = decodeStringArray(input);
		int[] array = new int[str.length];
		for (int i = 0; i < array.length; i++)
			array[i] = Integer.parseInt(str[i]);
		return array;
	}

	public static String encodeRectangle(Rectangle rect) {
		StringBuilder buf = new StringBuilder();
		buf.append(rect.x).append(SEPARATOR);
		buf.append(rect.y).append(SEPARATOR);
		buf.append(rect.width).append(SEPARATOR);
		buf.append(rect.height);
		return buf.toString();
	}

	public static Rectangle decodeRectangle(String rect) {
		String[] tokens = SPLITTER.split(rect);
		if (4 != tokens.length)
			throw new IllegalArgumentException("wrong rectangle format: " + rect);
		Rectangle r = new Rectangle();
		r.x = Integer.parseInt(tokens[0]);
		r.y = Integer.parseInt(tokens[1]);
		r.width = Integer.parseInt(tokens[2]);
		r.height = Integer.parseInt(tokens[3]);
		return r;
	}

	public static String encodeStringArray(String[] array) {
		StringBuilder buf = new StringBuilder();
		for (int i = 0; i < array.length; i++) {
			buf.append(array[i]);
			if (i < array.length - 1)
				buf.append(SEPARATOR);
		}
		return buf.toString();
	}

	public static String[] decodeStringArray(String input) {
		return SPLITTER.split(input);
	}

	/**
	 * ����ʮ������ַ��ʾ��<code>Color</code>.<br>
	 * �ַ������Color.decode(String)��ȡ
	 * 
	 * @param color
	 * @return
	 */
	public static String encodeColor(Color color) {
		char[] hex = new char[7];
		hex[0] = '#';
		Codec.unsignedByteToHex(color.getRed(), hex, 1);
		Codec.unsignedByteToHex(color.getGreen(), hex, 3);
		Codec.unsignedByteToHex(color.getBlue(), hex, 5);
		return new String(hex);
	}

	public static String encodeProxy(Proxy proxy) {
		StringBuilder buf = new StringBuilder();
		buf.append(proxy.type().name());
		buf.append('@').append(encodeSocketAddress(proxy.address()));
		return buf.toString();
	}

	public static Proxy decodeProxy(String input) {
		input = checkNotEmpty(input);
		if (null == input)
			return null;
		int index = input.indexOf('@');
		if (-1 == index)
			return null;
		return new Proxy(Proxy.Type.valueOf(input.substring(0, index)), decodeSocketAddress(input.substring(index + 1)));
	}

	public static String encodeSocketAddress(SocketAddress addr) {
		if (addr instanceof InetSocketAddress) {
			StringBuilder buf = new StringBuilder();
			InetSocketAddress a = (InetSocketAddress) addr;
			if (a.isUnresolved())
				buf.append(a.getHostName());
			else
				buf.append(a.getAddress().getHostAddress());
			buf.append(':').append(a.getPort());
			return buf.toString();
		} else
			return String.valueOf(addr);
	}

	public static SocketAddress decodeSocketAddress(String input) {
		input = checkNotEmpty(input);
		if (null == input)
			return null;
		int index = input.lastIndexOf(':');
		if (-1 == index)
			return null;
		return new InetSocketAddress(input.substring(0, index), Integer.parseInt(input.substring(index + 1)));
	}

	private static String checkNotEmpty(String str) {
		if (null == str)
			return null;
		str = str.trim();
		if (0 == str.length())
			return null;
		return str;
	}

	/*
	 * ��0~255֮����޷������ת����ʮ����ƣ������λ��'0'��ȫ
	 */
	private static void unsignedByteToHex(int b, char[] hex, int offset) {
		hex[offset] = HEX_DIGIT[b / 16];
		hex[++offset] = HEX_DIGIT[b % 16];
	}

	private Codec() {
	}
}
